from collections import defaultdict

from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import Max
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi

from .models import LayerGroup, LayerGroupMapping
from .serializers import (
    LayerGroupSerializer,
    CreateLayerGroupSerializer,
    UpdateLayerGroupSerializer,
    LayerGroupMappingSerializer,
    CreateLayerGroupMappingSerializer
)
from ..CanvasElementManagement.models import CanvasElement
from ..utils.response_utils import api_response, ResponseCode


# ==================== 图层组接口 ====================
class ListLayerGroupsView(APIView):
    """图层组列表接口"""

    @swagger_auto_schema(
        operation_description="获取图层组列表，可根据画布ID过滤",
        manual_parameters=[
            openapi.Parameter('canvas_id', openapi.IN_QUERY, type=openapi.TYPE_STRING,
                              description="画布ID，必填", required=True)
        ],
        responses={
            200: LayerGroupSerializer(many=True),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["图层组管理"]
    )
    def get(self, request):
        try:
            canvas_id = request.query_params.get('canvas_id')
            queryset = LayerGroup.objects.filter(canvas_id=canvas_id, parent__isnull=True).order_by('z_index')
            serializer = LayerGroupSerializer(queryset, many=True)
            return api_response(ResponseCode.SUCCESS, "获取成功", serializer.data)
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, str(e))


class CreateLayerGroupView(APIView):
    """创建图层组接口"""

    @swagger_auto_schema(
        operation_description="创建新图层组",
        request_body=CreateLayerGroupSerializer,
        responses={
            200: LayerGroupSerializer,
            400: openapi.Response(description="参数错误"),
        },
        tags=["图层组管理"]
    )
    def post(self, request):
        try:
            serializer = CreateLayerGroupSerializer(data=request.data)
            if serializer.is_valid():
                group = serializer.save()
                full_serializer = LayerGroupSerializer(group)
                return api_response(ResponseCode.SUCCESS, "创建成功", full_serializer.data)
            return api_response(ResponseCode.BAD_REQUEST, f"参数错误：{serializer.errors}")
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"服务器错误: {str(e)}")


class LayerGroupDetailView(APIView):
    """图层组详情接口"""

    @swagger_auto_schema(
        operation_description="获取图层组详情",
        manual_parameters=[
            openapi.Parameter('group_id', openapi.IN_PATH, type=openapi.TYPE_STRING,
                              description="图层组ID")
        ],
        responses={
            200: LayerGroupSerializer,
            404: openapi.Response(description="图层组不存在"),
        },
        tags=["图层组管理"]
    )
    def get(self, request, group_id):
        try:
            group = LayerGroup.objects.get(id=group_id)
            serializer = LayerGroupSerializer(group)
            return api_response(ResponseCode.SUCCESS, "获取成功", serializer.data)
        except ObjectDoesNotExist:
            return api_response(ResponseCode.NOT_FOUND, "图层组不存在")
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, str(e))


class UpdateLayerGroupView(APIView):
    """更新图层组接口"""

    @swagger_auto_schema(
        operation_description="更新图层组信息,不允许修改图层",
        request_body=UpdateLayerGroupSerializer,
        manual_parameters=[
            openapi.Parameter('group_id', openapi.IN_PATH, type=openapi.TYPE_STRING,
                              description="图层组ID")
        ],
        responses={
            200: LayerGroupSerializer,
            400: openapi.Response(description="参数错误"),
            404: openapi.Response(description="图层组不存在"),
        },
        tags=["图层组管理"]
    )
    def put(self, request, group_id):
        try:
            group = LayerGroup.objects.get(id=group_id)
            with transaction.atomic():
                serializer = UpdateLayerGroupSerializer(group, data=request.data, partial=True,
                                                        context={'request': request})
                serializer.is_valid(raise_exception=True)
                updated_group = serializer.save()
                full_serializer = LayerGroupSerializer(updated_group)
                return api_response(ResponseCode.SUCCESS, "更新成功", full_serializer.data)
        except ObjectDoesNotExist:
            return api_response(ResponseCode.NOT_FOUND, "图层组不存在")
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"服务器错误: {str(e)}")


class GroupOperationsView(APIView):
    @swagger_auto_schema(
        operation_description="组合/拆分组操作",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['operation', 'group_ids'],
            properties={
                'operation': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    enum=['merge', 'ungroup'],
                    description="操作类型：merge-合并，ungroup-拆分"
                ),
                'group_ids': openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(type=openapi.TYPE_STRING),
                    description="需要操作的组ID列表"
                ),
                'new_group_name': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    description="新组名称（合并时必填）"
                )
            }
        ),
        responses={
            200: LayerGroupSerializer,
            400: "参数错误",
            404: "部分组未找到"
        },
        tags=["图层组管理"]
    )
    def post(self, request):
        operation = request.data.get('operation')

        if operation == 'merge':
            return self._handle_merge(request)
        elif operation == 'ungroup':
            return self._handle_ungroup(request)
        else:
            return api_response(ResponseCode.BAD_REQUEST, "无效操作类型")

    def _handle_merge(self, request):
        group_ids = request.data.get('group_ids', [])
        new_group_name = request.data.get('new_group_name', 'New Group')

        try:
            with transaction.atomic():
                # 加锁确保原子性
                groups = LayerGroup.objects.select_for_update().filter(id__in=group_ids)
                mappings = []

                for group in groups:
                    if group.locked:
                        return api_response(ResponseCode.BAD_REQUEST, f"组 {group.name} 被锁定，无法合并")
                    elif not group.visible:
                        return api_response(ResponseCode.BAD_REQUEST, f"组 {group.name} 不可见，无法合并")

                    # 收集所有子组
                    def get_all_child_groups(g):
                        children = list(g.children.all())
                        for child in children:
                            children.extend(get_all_child_groups(child))
                        return children

                    all_child_groups = get_all_child_groups(group)
                    # 处理所有子组的元素映射
                    for child_group in [group] + all_child_groups:
                        if hasattr(child_group, 'elements_mapping') and child_group.elements_mapping.exists():
                            mappings.extend(child_group.elements_mapping.all())

                if groups.count() != len(group_ids):
                    missing = set(group_ids) - set(groups.values_list('id', flat=True))
                    return api_response(ResponseCode.NOT_FOUND, f"未找到组：{missing}")

                # 验证所有组必须同属一个父级和画布
                parent_ids = {g.parent_id for g in groups}
                if len(parent_ids) > 1:
                    return api_response(ResponseCode.BAD_REQUEST, "所有组必须属于同一父级")

                canvas_id = groups[0].canvas_id
                if any(g.canvas_id != canvas_id for g in groups):
                    return api_response(ResponseCode.BAD_REQUEST, "所有组必须属于同一画布")

                # 获取目标父级（与被合并组相同）
                target_parent_id = parent_ids.pop() if parent_ids else None

                # --- 第一步：重新排序未被合并的兄弟节点 ---
                # 获取未被合并的兄弟节点（排除当前要合并的组）
                siblings = LayerGroup.objects.filter(
                    parent_id=target_parent_id,
                    canvas_id=canvas_id
                ).exclude(id__in=group_ids).order_by('z_index', 'created_at')

                # 批量更新这些兄弟节点的 z_index 为连续值（0,1,2,...）
                for index, sibling in enumerate(siblings):
                    if sibling.z_index != index:
                        LayerGroup.objects.filter(id=sibling.id).update(z_index=index)

                # --- 第二步：创建新组并设置正确的 z_index ---
                # 新组的 z_index = 当前父级下未被合并兄弟的数量（即下一个位置）
                new_z_index = siblings.count()

                # 创建新组
                new_group = LayerGroup.objects.create(
                    canvas_id=canvas_id,
                    parent_id=target_parent_id,
                    name=new_group_name,
                    z_index=new_z_index,
                    visible=True,
                    locked=False
                )

                # --- 第三步：将被合并组移动到新组下并触发重新索引 ---
                groups.update(parent=new_group)

                # 获取新组下的所有子节点并按原顺序排序
                children = LayerGroup.objects.filter(parent=new_group).order_by('z_index', 'created_at')
                # 重新分配 z_index 从 0 开始
                child_ids = [child.id for child in children]
                child_z_indexes = list(range(len(children)))
                LayerGroup.objects.bulk_update_z_index(child_ids, child_z_indexes)

                elements_to_update = []
                for mapping in mappings:
                    element = mapping.element
                    if element.locked:
                        return api_response(ResponseCode.BAD_REQUEST, f"元素 {element.name} 被锁定，无法合并")
                    elif not element.visible:
                        return api_response(ResponseCode.BAD_REQUEST, f"元素 {element.name} 不可见，无法合并")
                    element.type = 'group'
                    element.group_parent_id = new_group.id
                    elements_to_update.append(element)
                # 批量保存更新后的元素
                if elements_to_update:
                    CanvasElement.objects.bulk_update(elements_to_update, ['type', 'group_parent_id'])

                return api_response(ResponseCode.SUCCESS, "合并成功", LayerGroupSerializer(new_group).data)

        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, str(e))

    def _handle_ungroup(self, request):
        group_ids = request.data.get('group_ids', [])

        try:
            groups = LayerGroup.objects.filter(id__in=group_ids)

            for group in groups:
                if group.locked:
                    return api_response(ResponseCode.BAD_REQUEST, f"组 {group.name} 被锁定，无法拆分")
                elif not group.visible:
                    return api_response(ResponseCode.BAD_REQUEST, f"组 {group.name} 不可见，无法拆分")

            if groups.count() != len(group_ids):
                missing = set(group_ids) - set(groups.values_list('id', flat=True))
                return api_response(ResponseCode.NOT_FOUND, f"未找到组：{missing}")

            # 校验所有组均有直接子节点
            for group in groups:
                if not LayerGroup.objects.filter(parent=group).exists():
                    return api_response(ResponseCode.BAD_REQUEST, f"组 {group.id} 无直接子节点，无法拆分")

            # 记录所有受影响的父级及其需要提升的子组
            affected_parents = defaultdict(list)

            with transaction.atomic():
                # 第一阶段：解除直接子组的关联，并记录目标父级
                for group in groups:
                    # 目标父级是原组的父级（可能是多层嵌套中的父级）
                    target_parent = group.parent
                    canvas = group.canvas
                    children_list = LayerGroup.objects.filter(parent=group).order_by('z_index', 'created_at')

                    elements_to_update = []
                    for child in children_list:
                        # 处理每个子组的元素
                        child_mappings = LayerGroupMapping.objects.filter(group=child)
                        for mapping in child_mappings:
                            element = mapping.element
                            if element.locked:
                                return api_response(ResponseCode.BAD_REQUEST, f"元素 {element.name} 被锁定，无法拆分")
                            elif not element.visible:
                                return api_response(ResponseCode.BAD_REQUEST, f"元素 {element.name} 不可见，无法拆分")

                            new_parent_id = target_parent.id if target_parent else None
                            # 根据 element 的类型设置属性
                            if target_parent is None:
                                if hasattr(element, 'text_element') and element.text_element:
                                    element.type = 'text'
                                elif hasattr(element, 'mask_element') and element.mask_element:
                                    element.type = 'mask'

                            element.group_parent_id = new_parent_id
                            elements_to_update.append(element)

                    if elements_to_update:
                        CanvasElement.objects.bulk_update(elements_to_update, ['type', 'group_parent_id'])

                    # 获取直接子组（仅一层，不递归）
                    direct_children = LayerGroup.objects.filter(parent=group).order_by('z_index', 'created_at')
                    direct_children_list = list(direct_children)

                    # 解除直接子组的父级关联（提升到 target_parent 层级）
                    direct_children.update(parent=target_parent)

                    # 记录目标父级和子组（用于重新索引）
                    affected_parents[(target_parent, canvas)].extend(direct_children_list)

                    # 删除当前组
                    group.delete()

                # 第二阶段：重新索引所有受影响的父级层级
                for (parent, canvas), children in affected_parents.items():
                    # 获取该父级下的所有兄弟节点（包含提升的子组）
                    siblings = LayerGroup.objects.filter(parent=parent, canvas=canvas).order_by('z_index', 'created_at')

                    # 重新分配 z_index
                    for index, sibling in enumerate(siblings):
                        if sibling.z_index != index:
                            LayerGroup.objects.filter(id=sibling.id).update(z_index=index)

            return api_response(ResponseCode.SUCCESS, "拆分成功")

        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, str(e))


class ChangeLayerGroupView(APIView):
    @swagger_auto_schema(
        operation_description="变换组图层",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['group_id', 'operation'],
            properties={
                'group_id': openapi.Schema(type=openapi.TYPE_STRING),
                'operation': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    enum=['increase', 'reduce'],
                    description="图层操作类型：increase-增加，reduce-减少"
                )
            }
        ),
        responses={
            200: openapi.Response(description="移动成功"),
            400: openapi.Response(description="参数错误"),
            404: openapi.Response(description="组未找到"),
        },
        tags=["图层组管理"]
    )
    def post(self, request):
        try:
            group = LayerGroup.objects.get(id=request.data['group_id'])

            if group.locked:
                return api_response(ResponseCode.BAD_REQUEST, f"组 {group.name} 被锁定，无法移动")

            new_position = 0
            operation = request.data['operation']
            if operation == 'increase':
                new_position = group.z_index + 1
            elif operation == 'reduce':
                new_position = group.z_index - 1

            parent = group.parent
            canvas = group.canvas

            siblings = LayerGroup.objects.filter(parent=parent, canvas=canvas)
            max_z = siblings.aggregate(max_z=Max('z_index'))['max_z']

            if new_position < 0 or new_position > max_z:
                return api_response(ResponseCode.BAD_REQUEST, "新位置超出范围")

            # 获取当前所有兄弟节点
            siblings = list(LayerGroup.objects.filter(
                parent=parent,
                canvas=canvas
            ).order_by('z_index'))

            # 移除当前组并插入新位置
            current_index = next(i for i, g in enumerate(siblings) if g.id == group.id)
            siblings.insert(new_position, siblings.pop(current_index))

            # 批量更新z_index
            for index, group in enumerate(siblings):
                if group.z_index != index:
                    group.z_index = index
                    group.save()

            serializers = LayerGroupSerializer(siblings, many=True)

            return api_response(ResponseCode.SUCCESS, "移动成功", serializers.data)
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, str(e))


class DeleteLayerGroupView(APIView):
    """删除图层组接口"""

    @swagger_auto_schema(
        operation_description="删除图层组",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['group_ids'],
            properties={
                'group_ids': openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(type=openapi.TYPE_STRING),
                    description="图层组ID列表"
                ),
            }
        ),
        responses={
            200: openapi.Response(description="删除成功"),
            404: openapi.Response(description="部分图层组不存在"),
        },
        tags=["图层组管理"]
    )
    def delete(self, request):
        group_ids = request.data.get('group_ids', [])
        if not group_ids or not isinstance(group_ids, list):
            return api_response(ResponseCode.BAD_REQUEST, "参数错误")

        not_found_ids = []
        for group_id in group_ids:
            try:
                group = LayerGroup.objects.get(id=group_id)
                group.delete()
            except ObjectDoesNotExist:
                not_found_ids.append(group_id)

        if not_found_ids:
            return api_response(
                ResponseCode.NOT_FOUND,
                f"成功删除图层组: {len(group_ids) - len(not_found_ids)}个，未找到ID: {', '.join(not_found_ids)}"
            )
        return api_response(ResponseCode.SUCCESS, "删除成功")


# ==================== 图层组关联接口 ====================
class ListLayerGroupMappingsView(APIView):
    """图层组关联列表接口"""

    @swagger_auto_schema(
        operation_description="获取图层组关联列表",
        manual_parameters=[
            openapi.Parameter('group_id', openapi.IN_QUERY, type=openapi.TYPE_STRING,
                              description="图层组ID", required=False),
            openapi.Parameter('element_id', openapi.IN_QUERY, type=openapi.TYPE_STRING,
                              description="元素ID", required=False)
        ],
        responses={
            200: LayerGroupMappingSerializer(many=True),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["图层组关联管理"]
    )
    def get(self, request):
        try:
            group_id = request.query_params.get('group_id')
            element_id = request.query_params.get('element_id')

            queryset = LayerGroupMapping.objects.all()
            if group_id:
                queryset = queryset.filter(group_id=group_id)
            if element_id:
                queryset = queryset.filter(element_id=element_id)

            serializer = LayerGroupMappingSerializer(queryset, many=True)
            return api_response(ResponseCode.SUCCESS, "获取成功", serializer.data)
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, str(e))


class CreateLayerGroupMappingView(APIView):
    """创建图层组关联接口"""

    @swagger_auto_schema(
        operation_description="创建图层组关联",
        request_body=CreateLayerGroupMappingSerializer,
        responses={
            200: LayerGroupMappingSerializer,
            400: openapi.Response(description="参数错误"),
        },
        tags=["图层组关联管理"]
    )
    def post(self, request):
        try:
            serializer = CreateLayerGroupMappingSerializer(data=request.data)
            if serializer.is_valid():
                mapping = serializer.save()
                full_serializer = LayerGroupMappingSerializer(mapping)
                return api_response(ResponseCode.SUCCESS, "创建成功", full_serializer.data)
            return api_response(ResponseCode.BAD_REQUEST, f"参数错误：{serializer.errors}")
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"服务器错误: {str(e)}")


class DeleteLayerGroupMappingView(APIView):
    """删除图层组关联接口"""

    @swagger_auto_schema(
        operation_description="删除关联记录",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['mappings'],
            properties={
                'mappings': openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(
                        type=openapi.TYPE_OBJECT,
                        properties={
                            'group': openapi.Schema(type=openapi.TYPE_STRING),
                            'element': openapi.Schema(type=openapi.TYPE_STRING)
                        }
                    ),
                    description="需删除的关联记录列表（包含group和element字段）"
                ),
            }
        ),
        responses={
            200: openapi.Response(description="删除成功"),
            404: openapi.Response(description="部分记录不存在"),
        },
        tags=["图层组关联管理"]
    )
    def delete(self, request):
        mappings = request.data.get('mappings', [])
        if not mappings or not isinstance(mappings, list):
            return api_response(ResponseCode.BAD_REQUEST, "参数错误")

        not_found = []
        for item in mappings:
            try:
                mapping = LayerGroupMapping.objects.get(group=item['group'], element=item['element'])
                mapping.delete()
            except ObjectDoesNotExist:
                not_found.append(f"{item['group']}-{item['element']}")

        if not_found:
            return api_response(
                ResponseCode.NOT_FOUND,
                f"成功删除关联记录: {len(mappings) - len(not_found)}个，未找到ID: {', '.join(not_found)}"
            )
        return api_response(ResponseCode.SUCCESS, "删除成功")
